home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Communications / pcomm / Source / dial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  8.5 KB  |  431 lines

  1. /*
  2.  * The routines that dial the modem and listen for the return codes.
  3.  */
  4.  
  5. #define HZ    60
  6. #undef USLEEP
  7.  
  8. #include <stdio.h>
  9. #include "config.h"
  10. #include "dial_dir.h"
  11. #include "misc.h"
  12. #include "modem.h"
  13. #include "param.h"
  14.  
  15. #ifdef BSD
  16. #include <sys/time.h>
  17. #else /* BSD */
  18. #include <sys/types.h>
  19. #include <sys/times.h>
  20. #endif /* BSD */
  21.  
  22. #ifdef UNIXPC
  23. #include <sys/phone.h>
  24. #endif /* UNIXPC */
  25.  
  26. /*
  27.  * Get the dial string ready, send it to the modem.  The parameter is not
  28.  * the actual entry number, it is an index into the queue.
  29.  */
  30.  
  31. void
  32. dial_it(num)
  33. int num;
  34. {
  35.     extern int fd;
  36.     int i, skip;
  37.     char s[100], number[40], *strcpy(), *strcat(), *n, *strchr();
  38.     void send_str();
  39. #ifdef UNIXPC
  40.     struct updata pbuf;
  41.     unsigned int sleep();
  42. #endif /* UNIXPC */
  43.  
  44.     /*
  45.      * Create the string to be sent to the modem.  The long distance
  46.      * codes are added if they are requested.
  47.      */
  48.     s[0] = '\0';
  49.     strcpy(s, modem->dial[modem->m_cur]);
  50.  
  51.     switch (dir->q_ld[num]) {
  52.         case 0:            /* no ld code requested */
  53.             break;
  54.         case '+':
  55.             strcat(s, param->ld_plus);
  56.             break;
  57.         case '-':
  58.             strcat(s, param->ld_minus);
  59.             break;
  60.         case '@':
  61.             strcat(s, param->ld_at);
  62.             break;
  63.         case '#':
  64.             strcat(s, param->ld_pound);
  65.             break;
  66.     }
  67.     /*
  68.      * Purify the phone number by removing all the pretty characters
  69.      * that don't need to be sent to the modem.  Typically the "-",
  70.      * "(", ")", and space characters are just for looks.  To prevent
  71.      * this action, prepend a "\" to the character.
  72.      */
  73.     i = 0;
  74.     skip = 0;
  75.     n = dir->number[dir->q_num[num]];
  76.     while (*n) {
  77.         if (*n == '\\' && !skip) {
  78.             skip++;
  79.             n++;
  80.             continue;
  81.         }
  82.         if (!strchr("-() ", *n) || skip)
  83.             number[i++] = *n;
  84.         n++;
  85.         skip = 0;
  86.     }
  87.     number[i] = '\0';
  88.                     /* add it to the string */
  89.     strcat(s, number);
  90.     strcat(s, modem->suffix[modem->m_cur]);
  91. #ifdef DEBUG
  92.     fprintf(stderr, "raw dial string: \"%s\"\n", s);
  93. #endif /* DEBUG */
  94.  
  95. #ifdef UNIXPC
  96.                     /* special case for OBM */
  97.     if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
  98.                     /* prepare the modem */
  99.         pbuf.c_lineparam = DATA|DTMF;
  100.         pbuf.c_waitdialtone = 5;
  101.         pbuf.c_linestatus = 0;
  102.         pbuf.c_feedback = SPEAKERON|NORMSPK;
  103.         pbuf.c_waitflash = 500;
  104.         ioctl(fd, PIOCSETP, &pbuf);
  105.         sleep(1);
  106.                     /* connect the dialer */
  107.         ioctl(fd, PIOCRECONN);
  108.         sleep(1);
  109.                     /* dial each digit */
  110.         n = s;
  111.         while (*n) {
  112.                     /* switch tone/pulse dialing? */
  113.             switch (*n) {
  114.                 case '^':
  115.                     pbuf.c_lineparam = DATA|PULSE;
  116.                     ioctl(fd, PIOCSETP, &pbuf);
  117.                     break;
  118.                 case '%':
  119.                     pbuf.c_lineparam = DATA|DTMF;
  120.                     ioctl(fd, PIOCSETP, &pbuf);
  121.                     break;
  122.                 default:
  123.                     ioctl(fd, PIOCDIAL, n);
  124.                     break;
  125.             }
  126.             n++;
  127.         }
  128.         /*
  129.          * It seems that the OBM doesn't always talk reliably to
  130.          * other types of modems (most notibly Telebits).  Here
  131.          * is some witchcraft to fix the problem.
  132.          */
  133.         ioctl(fd, PIOCOVSPD);
  134.         return;
  135.     }
  136. #endif /* UNIXPC */
  137.  
  138.     send_str(s, SLOW);
  139.     return;
  140. }
  141.  
  142. /*
  143.  * Send a string to the modem.  Performs all the character synonym
  144.  * translations.
  145.  */
  146.  
  147. void
  148. send_str(s, slow)
  149. char *s;
  150. int slow;
  151. {
  152.     extern int fd;
  153.     int skip, has_pause;
  154.     char *strchr();
  155.     unsigned int sleep();
  156.     static void do_pause();
  157.                     /* empty string? */
  158.     if (s == NULL || *s == '\0')
  159.         return;
  160.  
  161.                     /* contains a pause? */
  162.     has_pause = 0;
  163.     if (strchr(s, '~'))
  164.         has_pause++;
  165.  
  166.     tty_flush(fd, 1);
  167.     /*
  168.      * Change the character synonyms to their real values.  Writes
  169.      * the characters to the modem.  To remove the special meaning
  170.      * of one of the characters, prepend a "\" to it.
  171.      */
  172.     skip = 0;
  173.     while (*s) {
  174.                     /* send the literal character */
  175.         if (skip) {
  176.             skip = 0;
  177.             write(fd, s, 1);
  178.             if (has_pause || slow)
  179.                 tty_drain(fd);
  180.             if (slow)
  181.                 do_pause();
  182. #ifdef DEBUG
  183.             fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
  184. #endif /* DEBUG */
  185.             s++;
  186.             continue;
  187.         }
  188.                     /* turn off the special meaning */
  189.         if (*s == '\\') {
  190.             skip++;
  191.             s++;
  192.             continue;
  193.         }
  194.                     /* pause synonym */
  195.         if (*s == param->pause_char) {
  196.             sleep(1);
  197.             s++;
  198.             continue;
  199.         }
  200.                     /* carriage return synonym */
  201.         if (*s == param->cr_char)
  202.             *s = '\r';
  203.                     /* 2 character control sequence */
  204.         if (*s == param->ctrl_char) {
  205.             s++;
  206.                     /* premature EOF? */
  207.             if (*s == '\0')
  208.                 break;
  209.                     /* upper and lower case */
  210.             if (*s > '_')
  211.                 *s -= 96;
  212.             else
  213.                 *s -= 64;
  214.         }
  215.                     /* escape synonym */
  216.         if (*s == param->esc_char)
  217.             *s = ESC;
  218.                     /* modem break synonym */
  219.         if (*s == param->brk_char) {
  220.             tty_break(fd);
  221.             sleep(1);
  222.             s++;
  223.             continue;
  224.         }
  225.  
  226.         write(fd, s, 1);
  227. #ifdef DEBUG
  228.         fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
  229. #endif /* DEBUG */
  230.         /*
  231.          * Because the pause char makes the timing critical, we
  232.          * wait until the buffer is clear before we continue.
  233.          */
  234.         if (has_pause || slow)
  235.             tty_drain(fd);
  236.         if (slow)
  237.             do_pause();
  238.         s++;
  239.     }
  240.     return;
  241. }
  242.  
  243. /*
  244.  * Read the result codes coming back from the modem.  Test for the 6
  245.  * "connect" strings and the 4 "no connect" strings.  Return the connected
  246.  * baud rate (as a string) or the error message.
  247.  */
  248.  
  249. int rc_index;
  250.  
  251. char *
  252. read_codes()
  253. {
  254.     extern int fd;
  255.     int i;
  256.     static int match();
  257.     char c;
  258.     static char rc_buf[512];
  259. #ifdef UNIXPC
  260.     unsigned int sleep();
  261.     struct updata pbuf;
  262.                     /* special case for OBM */
  263.     if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
  264.         ioctl(fd, PIOCGETP, &pbuf);
  265.  
  266.         /*
  267.          * The OBM doesn't use a return message to announce the
  268.          * connection to a remote, so we fake one.  The 1200
  269.          * is quite arbitrary... it is not an indicator of the
  270.          * connected baud rate.
  271.          */
  272.         if (pbuf.c_linestatus & MODEMCONNECTED)
  273.             return("1200");
  274.  
  275.         sleep(1);
  276.         return(NULL);
  277.     }
  278. #endif /* UNIXPC */
  279.                     /* search for key words */
  280.     for (; rc_index<511; rc_index++) {
  281.         if ((i = getc_line(1)) <= 0)
  282.             return(NULL);
  283.  
  284.         c = i & 0x7f;
  285. #ifdef DEBUG
  286.         fprintf(stderr, "read_codes: \"%c\", %02x, %03o, %d\n", c, c, c, c);
  287. #endif /* DEBUG */
  288.                     /* no NULLs please */
  289.         if (c == '\0') {
  290.             if (rc_index)
  291.                 rc_index--;
  292.             continue;
  293.         }
  294.         rc_buf[rc_index] = c;
  295.         rc_buf[rc_index+1] = '\0';
  296.                     /* the connect strings */
  297.         if (match(rc_buf, modem->con_3[modem->m_cur]))
  298.             return("300");
  299.  
  300.         if (match(rc_buf, modem->con_12[modem->m_cur]))
  301.             return("1200");
  302.  
  303.         if (match(rc_buf, modem->con_24[modem->m_cur]))
  304.             return("2400");
  305.  
  306.         if (match(rc_buf, modem->con_48[modem->m_cur]))
  307.             return("4800");
  308.  
  309.         if (match(rc_buf, modem->con_96[modem->m_cur]))
  310.             return("9600");
  311.  
  312.         if (match(rc_buf, modem->con_192[modem->m_cur]))
  313.             return("19200");
  314.  
  315.                     /* the no connect strings */
  316.         if (match(rc_buf, modem->no_con1[modem->m_cur]))
  317.             return(modem->no_con1[modem->m_cur]);
  318.  
  319.         if (match(rc_buf, modem->no_con2[modem->m_cur]))
  320.             return(modem->no_con2[modem->m_cur]);
  321.  
  322.         if (match(rc_buf, modem->no_con3[modem->m_cur]))
  323.             return(modem->no_con3[modem->m_cur]);
  324.  
  325.         if (match(rc_buf, modem->no_con4[modem->m_cur]))
  326.             return(modem->no_con4[modem->m_cur]);
  327.     }
  328.                     /* ran out of buffer? */
  329.     return("ERROR");
  330. }
  331.  
  332. /*
  333.  * Test for a match between two character strings.  A non-zero return code
  334.  * means that s2 was found at the end of s1.
  335.  */
  336.  
  337. static int
  338. match(s1, s2)
  339. char *s1, *s2;
  340. {
  341.     register int i;
  342.     int skip, diff;
  343.     char new[40];
  344.                     /* if no string to match */
  345.     if (*s2 == '\0')
  346.         return(0);
  347.                     /* translate synonyms */
  348.     i = 0;
  349.     skip = 0;
  350.     while (*s2) {
  351.                     /* literal character */
  352.         if (skip) {
  353.             skip = 0;
  354.             new[i++] = *s2;
  355.             s2++;
  356.             continue;
  357.         }
  358.                     /* turn off the special meaning */
  359.         if (*s2 == '\\') {
  360.             skip++;
  361.             s2++;
  362.             continue;
  363.         }
  364.                     /* carriage return synonym */
  365.         if (*s2 == param->cr_char)
  366.             *s2 = '\r';
  367.  
  368.                     /* 2 character control sequence */
  369.         if (*s2 == param->ctrl_char) {
  370.             s2++;
  371.             if (*s2 == '\0')
  372.                 break;
  373.             if (*s2 > '_')
  374.                 *s2 -= 96;
  375.             else
  376.                 *s2 -= 64;
  377.         }
  378.                     /* escape synonym */
  379.         if (*s2 == param->esc_char)
  380.             *s2 = ESC;
  381.  
  382.         new[i++] = *s2;
  383.         s2++;
  384.     }
  385.     new[i] = '\0';
  386.  
  387.     diff = strlen(s1) - strlen(new);
  388.                     /* is it possible? */
  389.     if (diff < 0)
  390.         return(0);
  391.                     /* test it out */
  392.     if (!strcmp(&s1[diff], new))
  393.         return(1);
  394.     return(0);
  395. }
  396.  
  397. /*
  398.  * Apparently some modems can't take input at the rated speed while
  399.  * in the command mode.  Therefore, a 0.10 sec pause a required between
  400.  * characters.
  401.  */
  402.  
  403. static void
  404. do_pause()
  405. {
  406. #ifdef USLEEP
  407.     usleep(100000);
  408. #else /* USLEEP */
  409.                 /* Hey! I know these routines are a hack */
  410. #ifdef BSD
  411.     struct timeval tv;
  412.     struct timezone tz;
  413.     double t1;
  414.  
  415.     gettimeofday(&tv, &tz);
  416.     t1 = tv.tv_sec + (tv.tv_usec / 1000000.0);
  417.     do
  418.         gettimeofday(&tv, &tz);
  419.     while ((tv.tv_sec + (tv.tv_usec / 1000000.0) - t1) < 0.1);
  420. #else /* BSD */
  421.     struct tms t;
  422.     long t1;
  423.  
  424.     t1 = times(&t);
  425.     while ((times(&t) - t1) < HZ/10)
  426.         ;
  427. #endif /* BSD */
  428. #endif /* USLEEP */
  429.     return;
  430. }
  431.